//------------------------------------------------------------------------------
//  Namespace: FruitVentDesign.Controls
//  
//  Function： N/A
//  Name： Select
//  
//  Ver       Time                     Author
//  0.10      2021/6/21 12:18:34      FruitVent
//
//  此代码版权归作者本人FruitVent所有
//  源代码使用协议遵循本仓库的开源协议及附加协议，若本仓库没有设置，则按MIT开源协议授权
//  CSDN博客：https://blog.csdn.net/weixin_39552347
//  源代码仓库：https://gitee.com/fruitvent
//  感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;
using WPFTemplateLib.Controls.FruitVentDesign.Commands;

namespace WPFTemplateLib.Controls.FruitVentDesign
{
    public class Select : ComboBox
    {
        static Select()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(Select), new FrameworkPropertyMetadata(typeof(Select)));
            //var defaultMetadata = ComboBox.TextProperty.GetMetadata(typeof(ComboBox));

            //ComboBox.TextProperty.OverrideMetadata(typeof(Select), new FrameworkPropertyMetadata(
            //    string.Empty, FrameworkPropertyMetadataOptions.Journal | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
            //    defaultMetadata.PropertyChangedCallback,
            //    defaultMetadata.CoerceValueCallback,
            //    true,
            //    UpdateSourceTrigger.PropertyChanged));
        }

        public Select()
        {
            Loaded += TreeSelect_Loaded;
        }

        private void TreeSelect_Loaded(object sender, RoutedEventArgs e)
        {
            if (ShowSearch)
            {
                PresetPlaceholderValue = Placeholder_TextBolck.Text;
                OriginalItemsSource = ItemsSource;
            }
        }

        private Popup popup;
        private Border PART_Placeholder;
        private TextBox PART_EditableTextBox;
        private TextBlock Placeholder_TextBolck;
        private ToggleButton PART_DropDownButton;
        public object PreviousSelectedItem { get; set; } = null;
        private string PresetPlaceholderValue { get; set; } = string.Empty;
        private IEnumerable OriginalItemsSource { get; set; } = null;

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            popup = Template.FindName("PART_Popup", this) as Popup;
            PART_Placeholder = Template.FindName("PART_Placeholder", this) as Border;
            PART_EditableTextBox = Template.FindName("PART_EditableTextBox", this) as TextBox;
            PART_DropDownButton = Template.FindName("PART_DropDownButton", this) as ToggleButton;
            if (PART_Placeholder.Child is TextBlock placeholder)
            {
                Placeholder_TextBolck = placeholder;
            }

            PART_EditableTextBox.TextChanged += PART_EditableTextBox_TextChanged;
            PART_EditableTextBox.PreviewMouseLeftButtonUp += PART_EditableTextBox_PreviewMouseLeftButtonUp;
            PART_DropDownButton.PreviewMouseLeftButtonUp += PART_DropDownButton_PreviewMouseLeftButtonUp;
            popup.Closed += Popup_Closed;
        }

        /// <summary>
        /// 输入框鼠标左键点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PART_EditableTextBox_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (!IsDropDownOpen)
            {
                IsDropDownOpen = true;
            }
        }

        /// <summary>
        /// 下拉框收起事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Popup_Closed(object sender, EventArgs e)
        {
            if (ShowSearch)
            {
                PART_EditableTextBox.Text = string.Empty;
                PART_EditableTextBox.Visibility = Visibility.Collapsed;
                IsReadOnly = true;
                if (SelectedItem == null && PreviousSelectedItem != null)
                {
                    SelectedItem = PreviousSelectedItem;
                }
            }
        }

        /// <summary>
        /// 下拉按钮鼠标点击抬起事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PART_DropDownButton_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (ShowSearch && IsDropDownOpen)
            {
                if (!string.IsNullOrEmpty(Text))
                {
                    Placeholder_TextBolck.Text = Text;
                }
                else
                {
                    Placeholder_TextBolck.Text = PresetPlaceholderValue;
                }

                PART_EditableTextBox.Visibility = Visibility.Visible;
                IsReadOnly = false;
                _ = PART_EditableTextBox.Focus();
            }
        }

        /// <summary>
        /// 输入框内容发生改变时
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PART_EditableTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (sender is TextBox input)
            {
                if (string.IsNullOrEmpty(input.Text))
                {
                    ItemsSource = OriginalItemsSource;
                }
                else
                {
                    ItemsSource = DoFilter(input.Text);
                }
            }
        }

        /// <summary>
        /// 获得筛选结果
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        private IEnumerable DoFilter(string text)
        {
            List<object> filterItems = new List<object>();
            if (SearchPath == null && OriginalItemsSource != null)
            {
                foreach (object item in OriginalItemsSource)
                {
                    if (item is string str)
                    {
                        if (str.ToLower().IndexOf(text.ToLower()) >= 0)
                        {
                            filterItems.Add(item);
                        }
                    }
                }
            }
            else
            {
                foreach (object item in OriginalItemsSource)
                {
                    Type type = item.GetType();
                    PropertyInfo filterPorperty = type.GetProperty(SearchPath.ToString(), BindingFlags.Instance | BindingFlags.Public);
                    if(filterPorperty != null && filterPorperty.CanRead)
                    {
                        string value = filterPorperty.GetValue(item).ToString();
                        if (value.ToLower().IndexOf(text.ToLower()) >= 0)
                        {
                            filterItems.Add(item);
                        }
                    }
                }
            }

            return filterItems;
        }

        /// <summary>
        /// 当中项发生改变时
        /// </summary>
        /// <param name="e"></param>
        protected override void OnSelectionChanged(SelectionChangedEventArgs e)
        {
            base.OnSelectionChanged(e);
            if(e.AddedItems.Count > 0)
            {
                PreviousSelectedItem = e.AddedItems[0];
            }
        }

        #region HasErrorMessage 验证通过与否字段
        /// <summary>
        /// 验证通过与否字段
        /// </summary>
        public static readonly DependencyProperty HasErrorMessageProperty = DependencyProperty.Register(
            "HasErrorMessage", typeof(bool), typeof(Select), new FrameworkPropertyMetadata(false,
                FrameworkPropertyMetadataOptions.Journal | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                new PropertyChangedCallback(OnHasErrorMessagePropertyChanged)));

        private static void OnHasErrorMessagePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            var oldValue = (object)args.OldValue;
            var newValue = (object)args.NewValue;

            if (oldValue == newValue)
                return;

            if ((bool)newValue)
            {
                if (obj is FrameworkElement content && content.Parent is Form form)
                {
                    if (form.ItemContainerGenerator.ContainerFromItem(content) is FormItem formItem)
                    {
                        formItem.HasErrorMessage = true;
                        var binding = new Binding(nameof(FormItem.ErrorMessage))
                        {
                            Source = content,
                            Mode = BindingMode.TwoWay,
                            Path = new PropertyPath("(Validation.Errors).CurrentItem.ErrorContent")
                        };
                        formItem.SetBinding(FormItem.ErrorMessageProperty, binding);
                    }
                }
            }
            else
            {
                if (obj is FrameworkElement content && content.Parent is Form form)
                {
                    if (form.ItemContainerGenerator.ContainerFromItem(content) is FormItem formItem)
                    {
                        formItem.HasErrorMessage = false;
                    }
                }
            }
        }

        public bool HasErrorMessage
        {
            get { return (bool)GetValue(HasErrorMessageProperty); }
            set { SetValue(HasErrorMessageProperty, value); }
        }

        public static void SetHasErrorMessage(DependencyObject element, bool value)
        {
            element.SetValue(HasErrorMessageProperty, value);
        }

        public static bool GetHasErrorMessage(DependencyObject element)
        {
            return (bool)element.GetValue(HasErrorMessageProperty);
        }
        #endregion

        #region PlaceholderProperty 占位符
        /// <summary>
        /// 占位符
        /// </summary>
        public static readonly DependencyProperty PlaceholderProperty = DependencyProperty.Register(
            "Placeholder", typeof(string), typeof(Select), new FrameworkPropertyMetadata(""));

        public string Placeholder
        {
            get { return (string)GetValue(PlaceholderProperty); }
            set { SetValue(PlaceholderProperty, value); }
        }

        public static string GetPlaceholder(DependencyObject d)
        {
            return (string)d.GetValue(PlaceholderProperty);
        }

        public static void SetPlaceholder(DependencyObject obj, string value)
        {
            obj.SetValue(PlaceholderProperty, value);
        }
        #endregion

        #region CornerRadiusProperty Border圆角
        /// <summary>
        /// Border圆角
        /// </summary>
        public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached(
            "CornerRadius", typeof(CornerRadius), typeof(Select), new FrameworkPropertyMetadata(new CornerRadius(3)));

        public CornerRadius CornerRadius
        {
            get { return (CornerRadius)GetValue(CornerRadiusProperty); }
            set { SetValue(CornerRadiusProperty, value); }
        }

        public static CornerRadius GetCornerRadius(DependencyObject d)
        {
            return (CornerRadius)d.GetValue(CornerRadiusProperty);
        }

        public static void SetCornerRadius(DependencyObject obj, CornerRadius value)
        {
            obj.SetValue(CornerRadiusProperty, value);
        }
        #endregion

        #region FocusBorderBrushProperty 焦点边框色，输入控件
        /// <summary>
        /// 焦点边框色，输入控件
        /// </summary>
        public static readonly DependencyProperty FocusBorderBrushProperty = DependencyProperty.Register(
            "FocusBorderBrush", typeof(Brush), typeof(Select), new FrameworkPropertyMetadata(null));

        public Brush FocusBorderBrush
        {
            get { return (Brush)GetValue(FocusBorderBrushProperty); }
            set { SetValue(FocusBorderBrushProperty, value); }
        }

        public static void SetFocusBorderBrush(DependencyObject element, Brush value)
        {
            element.SetValue(FocusBorderBrushProperty, value);
        }

        public static Brush GetFocusBorderBrush(DependencyObject element)
        {
            return (Brush)element.GetValue(FocusBorderBrushProperty);
        }
        #endregion

        #region MouseOverBorderBrushProperty 鼠标进入边框色，输入控件
        /// <summary>
        /// 鼠标进入边框色，输入控件
        /// </summary>
        public static readonly DependencyProperty MouseOverBorderBrushProperty = DependencyProperty.Register(
            "MouseOverBorderBrush", typeof(Brush), typeof(Select),
            new FrameworkPropertyMetadata(Brushes.Transparent,
            FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits));

        public Brush MouseOverBorderBrush
        {
            get { return (Brush)GetValue(MouseOverBorderBrushProperty); }
            set { SetValue(MouseOverBorderBrushProperty, value); }
        }

        /// <summary>
        /// Sets the brush used to draw the mouse over brush.
        /// </summary>
        public static void SetMouseOverBorderBrush(DependencyObject obj, Brush value)
        {
            obj.SetValue(MouseOverBorderBrushProperty, value);
        }

        /// <summary>
        /// Gets the brush used to draw the mouse over brush.
        /// </summary>
        public static Brush GetMouseOverBorderBrush(DependencyObject obj)
        {
            return (Brush)obj.GetValue(MouseOverBorderBrushProperty);
        }
        #endregion

        #region AllowClearProperty 清除输入框Text值按钮启用
        /// <summary>
        /// 清除输入框Text值按钮显示与否
        /// </summary>
        public static readonly DependencyProperty AllowClearProperty = DependencyProperty.RegisterAttached(
            "AllowClear", typeof(bool), typeof(Select), new FrameworkPropertyMetadata(false, AllowClearChanged));

        public bool AllowClear
        {
            get { return (bool)GetValue(AllowClearProperty); }
            set { SetValue(AllowClearProperty, value); }
        }

        /// <summary>
        /// Gets the brush used to draw the mouse over brush.
        /// </summary>
        public static bool GetAllowClear(DependencyObject d)
        {
            return (bool)d.GetValue(AllowClearProperty);
        }

        public static void SetAllowClear(DependencyObject obj, bool value)
        {
            obj.SetValue(AllowClearProperty, value);
        }

        private static void AllowClearChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.OldValue != e.NewValue && d is Button button)
            {
                button.CommandBindings.Add(RoutedUICommands.ClearTextCommandBinding);
            }
        }
        #endregion

        #region ShowSearchProperty 是否可搜索字段
        /// <summary>
        /// 是否可搜索字段
        /// </summary>
        public static readonly DependencyProperty ShowSearchProperty = DependencyProperty.Register(
            "ShowSearch", typeof(bool), typeof(Select), new FrameworkPropertyMetadata(false));

        public bool ShowSearch
        {
            get { return (bool)GetValue(ShowSearchProperty); }
            set { SetValue(ShowSearchProperty, value); }
        }

        public static bool GetShowSearch(DependencyObject d)
        {
            return (bool)d.GetValue(ShowSearchProperty);
        }

        public static void SetShowSearch(DependencyObject obj, bool value)
        {
            obj.SetValue(ShowSearchProperty, value);
        }
        #endregion

        #region ShowSearchProperty 搜索关键字绑定
        /// <summary>
        /// 搜索关键字绑定
        /// </summary>
        public static readonly DependencyProperty SearchPathProperty = DependencyProperty.Register(
            "SearchPath", typeof(object), typeof(Select), new FrameworkPropertyMetadata(null));

        public object SearchPath
        {
            get { return GetValue(SearchPathProperty); }
            set { SetValue(SearchPathProperty, value); }
        }

        public static object GetSearchPath(DependencyObject d)
        {
            return d.GetValue(SearchPathProperty);
        }

        public static void SetSearchPath(DependencyObject obj, object value)
        {
            obj.SetValue(SearchPathProperty, value);
        }
        #endregion
    }
}
